﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Net.Http.Headers;
using System.Collections.Specialized;
using WebSelfHost.Web.Filters;
using WebSelfHost.Web.Controllers;
using WebSelfHost.Utility.Core;
using WebSelfHost.Utility.Extension;
using WebSelfHost.Utility.Other;
using WebSelfHost.Utility.Web;
using WebSelfHost.Utility.Files;
#if NETFRAMEWORK
using System.Web.Http;
using OwinSessionMiddleware.WebApi;
using System.Net.Http;
using System.Net;
#else
using Microsoft.AspNetCore.Http;
#endif

namespace CentralControl.Service.Controllers
{
    [HiddenApi]
    public class UEditorController : BaseController
    {

        [HttpPost, HttpGet, Route("api/UEditor")] //配置路由
        public ActionResult UEditorHandler()
        {
            string action = "";
            string callback = "";
#if NETFRAMEWORK
            List<KeyValuePair<string, string>> parms = Request.GetQueryNameValuePairs().ToList();
            action = parms.Where(it => it.Key == "action").Select(it => it.Value).FirstOrDefault();
            callback = parms.Where(it => it.Key == "callback").Select(it => it.Value).FirstOrDefault();
#else
            action = HttpContext.Request.Query["action"];
            callback = HttpContext.Request.Query["callback"];
#endif
            if (action == "config")
            {
                return WriteJson(Config.Items, callback);
            }
            else if (action == "uploadimage")
            {
                return UploadHandler(new UploadConfig
                {
                    AllowExtensions = Config.GetStringList("imageAllowFiles").ToList(),
                    PathFormat = Config.GetString("imagePathFormat"),
                    SizeLimit = Config.GetInt("imageMaxSize"),
                    UploadFieldName = Config.GetString("imageFieldName")
                }, callback);
            }
            else if (action == "uploadscrawl")
            {
                return UploadHandler(new UploadConfig
                {
                    AllowExtensions = new string[] { ".png" }.ToList(),
                    PathFormat = Config.GetString("scrawlPathFormat"),
                    SizeLimit = Config.GetInt("scrawlMaxSize"),
                    UploadFieldName = Config.GetString("scrawlFieldName"),
                    Base64 = true,
                    Base64Filename = "scrawl.png"
                }, callback);
            }
            else if (action == "uploadvideo")
            {
                return UploadHandler(new UploadConfig
                {
                    AllowExtensions = Config.GetStringList("videoAllowFiles").ToList(),
                    PathFormat = Config.GetString("videoPathFormat"),
                    SizeLimit = Config.GetInt("videoMaxSize"),
                    UploadFieldName = Config.GetString("videoFieldName")
                }, callback);
            }
            else if (action == "uploadfile")
            {
                return UploadHandler(new UploadConfig
                {
                    AllowExtensions = Config.GetStringList("fileAllowFiles").ToList(),
                    PathFormat = Config.GetString("filePathFormat"),
                    SizeLimit = Config.GetInt("fileMaxSize"),
                    UploadFieldName = Config.GetString("fileFieldName")
                }, callback);
            }
            else if (action == "listimage")
            {
                return ListFileManager(Config.GetString("imageManagerListPath"), Config.GetStringList("imageManagerAllowFiles"), callback);

            }
            else if (action == "listfile")
            {
                return ListFileManager(Config.GetString("fileManagerListPath"), Config.GetStringList("fileManagerAllowFiles"), callback);
            }
            else if (action == "catchimage")
            {
                return Content(new { state = "action is empty or action not supperted." }.ToJson());
            }
            else
            {
                return Content(new { state = "action is empty or action not supperted." }.ToJson());
            }
        }

        private ActionResult ListFileManager(string pathToList, string[] searchExtensions, string callback)
        {
            List<string> SearchExtensions = searchExtensions.Select(it => it.ToLower()).ToList();
            int Start;
            int Size;
            try
            {
#if !NETFRAMEWORK
                string start = Request.Query["start"];
                string size = Request.Query["size"];
                Start = (string.IsNullOrEmpty(start) ? 0 : Convert.ToInt32(start));
                Size = (string.IsNullOrEmpty(size) ? Config.GetInt("imageManagerListSize") : Convert.ToInt32(size));
#else
                List<KeyValuePair<string, string>> parms = Request.GetQueryNameValuePairs().ToList();
                string start = parms.Where(it => it.Key == "start").Select(it => it.Value).FirstOrDefault();
                string size = parms.Where(it => it.Key == "size").Select(it => it.Value).FirstOrDefault();
                Start = (string.IsNullOrEmpty(start) ? 0 : Convert.ToInt32(start));
                Size = (string.IsNullOrEmpty(size) ? Config.GetInt("imageManagerListSize") : Convert.ToInt32(size));
#endif
            }
            catch (FormatException)
            {
                return WriteJson(new { state = "参数不正确", start = 0, size = 0, total = 0 }, callback);
            }
            try
            {
                string localPath = Path.Combine(MyEnvironment.WebRootPath(""), pathToList);
                List<string> list = Directory.GetFiles(localPath, "*", SearchOption.AllDirectories).Where(it => SearchExtensions.Contains(Path.GetExtension(it).ToLower())).Select(it => pathToList + it.Substring(localPath.Length).Replace("\\", "/")).ToList();
                int total = list.Count;
                List<string> FileList = list.OrderBy(it => it).Skip(Start).Take(Size).ToList();
                return WriteJson(new { state = "SUCCESS", start = Start, size = Size, total = total, list = FileList.Select(it => new { url = it }).ToList() }, callback);
            }
            catch (UnauthorizedAccessException)
            {
                return WriteJson(new { state = "文件系统权限不足", start = 0, size = 0, total = 0 }, callback);
            }
            catch (DirectoryNotFoundException)
            {
                return WriteJson(new { state = "路径不存在", start = 0, size = 0, total = 0 }, callback);
            }
            catch (IOException)
            {
                return WriteJson(new { state = "文件系统读取错误", start = 0, size = 0, total = 0 }, callback);
            }
        }

        public ActionResult WriteJson(object obj, string callback)
        {
            if (string.IsNullOrWhiteSpace(callback))
            {
                return ContentType(obj.ToJson(), "text/plain");
            }
            else
            {
                return ContentType(string.Format("{0}({1});", callback, obj.ToJson()), "application/javascript");
            }
        }

        public ActionResult UploadHandler(UploadConfig config, string callback)
        {
            List<string> allowExtensions = config.AllowExtensions;
            string pathFormat = config.PathFormat;
            int sizeLimit = config.SizeLimit;
            string uploadFieldName = config.UploadFieldName;
            string originFileName = "";
            byte[] array = null;

            if (config.Base64)
            {
                originFileName = config.Base64Filename;
#if !NETFRAMEWORK
                array = Convert.FromBase64String(base.Request.Form[config.UploadFieldName]);
#else
                NameValueCollection NameValueCollection = Request.Content.ReadAsFormDataAsync().Result;
                array = Convert.FromBase64String(NameValueCollection[config.UploadFieldName]);
#endif
                if (!allowExtensions.Select(it => it.ToLower()).ToList().Contains(Path.GetExtension(originFileName).ToLower()))
                {
                    return WriteJson(new { state = "不允许的文件格式", url = "", title = "", original = "", error = "" }, callback);
                }
                if ((int)array.Length > sizeLimit)
                {
                    return WriteJson(new { state = "文件大小超出服务器限制", url = "", title = "", original = "", error = "" }, callback);
                }
                string url = PathFormatter(originFileName, pathFormat);
                string path = Path.Combine(MyEnvironment.WebRootPath(""), url);
                if (!Directory.Exists(Path.GetDirectoryName(path)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(path));
                }
                try
                {
                    using (FileStream fs = System.IO.File.Create(path))
                    {
                        fs.Write(array, 0, array.Length);
                        fs.Flush();
                    }
                    return WriteJson(new { state = "SUCCESS", url = url, title = "", original = originFileName, error = "" }, callback);
                }
                catch (Exception ex)
                {
                    return WriteJson(new { state = "文件访问出错，请检查写入权限", url = "", title = "", original = originFileName, error = ex.Message }, callback);
                }

            }
            else
            {

#if !NETFRAMEWORK
                IFormFile formFile = base.Request.Form.Files[uploadFieldName];
                originFileName = formFile.FileName;
                if (!allowExtensions.Select(it => it.ToLower()).ToList().Contains(Path.GetExtension(originFileName).ToLower()))
                {
                    return WriteJson(new { state = "不允许的文件格式", url = "", title = "", original = "", error = "" }, callback);
                }
                if ((int)formFile.Length > sizeLimit)
                {
                    return WriteJson(new { state = "文件大小超出服务器限制", url = "", title = "", original = "", error = "" }, callback);
                }
                string url = PathFormatter(originFileName, pathFormat);
                string path = Path.Combine(MyEnvironment.WebRootPath(""), url);
                if (!Directory.Exists(Path.GetDirectoryName(path)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(path));
                }
                try
                {
                    FileUtil.Save(formFile, path);
                    return WriteJson(new { state = "SUCCESS", url = url, title = "", original = originFileName, error = "" }, callback);
                }
                catch (Exception ex)
                {
                    return WriteJson(new { state = "文件访问出错，请检查写入权限", url = "", title = "", original = originFileName, error = ex.Message }, callback);
                }
#else
                if (!Request.Content.IsMimeMultipartContent())
                {
                    return WriteJson(new { state = "网络错误", url = "", title = "", original = "", error = "" }, callback);
                }
                try
                {
                    string temppath = MyEnvironment.WebRootPath("/Uploads/"); //临时存放
                    var provider = new WithExtensionMultipartFormDataStreamProvider(temppath, UUID.StrSnowId);
                    var fileData = Request.Content.ReadAsMultipartAsync(provider).Result;
                    if (fileData.FileData.Count == 0)
                    {
                        return WriteJson(new { state = "网络错误", url = "", title = "", original = "", error = "" }, callback);
                    }
                    var file = fileData.FileData[0];
                    string virtualPath = "/Uploads/" + Path.GetFileName(file.LocalFileName);
                    string absPath = MyEnvironment.WebRootPath(virtualPath);

                    originFileName = provider.OriginalName;
                    if (!allowExtensions.Select(it => it.ToLower()).ToList().Contains(Path.GetExtension(originFileName).ToLower()))
                    {
                        return WriteJson(new { state = "不允许的文件格式", url = "", title = "", original = "", error = "" }, callback);
                    }
                    byte[] FileByte = System.IO.File.ReadAllBytes(absPath);
                    System.IO.File.Delete(absPath);
                    if (FileByte.Length > sizeLimit)
                    {
                        return WriteJson(new { state = "文件大小超出服务器限制", url = "", title = "", original = "", error = "" }, callback);
                    }
                    string url = PathFormatter(originFileName, pathFormat);
                    string path = Path.Combine( MyEnvironment.WebRootPath(""), url);
                    if (!Directory.Exists(Path.GetDirectoryName(path)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(path));
                    }
                    try
                    {
                        using (FileStream fs = System.IO.File.Create(path))
                        {
                            fs.Write(FileByte, 0, FileByte.Length);
                            fs.Flush();
                        }
                        return WriteJson(new { state = "SUCCESS", url = url, title = "", original = originFileName, error = "" }, callback);
                    }
                    catch (Exception ex)
                    {
                        return WriteJson(new { state = "文件访问出错，请检查写入权限", url = "", title = "", original = originFileName, error = ex.Message }, callback);
                    }
                }
                catch (Exception ex)
                {
                    return WriteJson(new { state = "网络错误", url = "", title = "", original = "", error = "" }, callback);
                }
#endif
            }

        }

        public string PathFormatter(string originFileName, string pathFormat)
        {
            if (string.IsNullOrWhiteSpace(pathFormat))
            {
                pathFormat = "{filename}{rand:6}";
            }
            Regex regex = new Regex("[\\\\\\/\\:\\*\\?\\042\\<\\>\\|]");
            originFileName = regex.Replace(originFileName, "");
            string extension = Path.GetExtension(originFileName);
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(originFileName);
            pathFormat = pathFormat.Replace("{filename}", fileNameWithoutExtension);
            pathFormat = new Regex("\\{rand(\\:?)(\\d+)\\}", RegexOptions.Compiled).Replace(pathFormat, delegate (Match match)
            {
                int num = 6;
                if (match.Groups.Count > 2)
                {
                    num = Convert.ToInt32(match.Groups[2].Value);
                }
                Random random = new Random();
                return random.Next((int)Math.Pow(10.0, (double)num), (int)Math.Pow(10.0, (double)(num + 1))).ToString();
            });
            pathFormat = pathFormat.Replace("{time}", DateTime.Now.Ticks.ToString());
            pathFormat = pathFormat.Replace("{yyyy}", DateTime.Now.Year.ToString());
            pathFormat = pathFormat.Replace("{yy}", (DateTime.Now.Year % 100).ToString("D2"));
            pathFormat = pathFormat.Replace("{mm}", DateTime.Now.Month.ToString("D2"));
            pathFormat = pathFormat.Replace("{dd}", DateTime.Now.Day.ToString("D2"));
            pathFormat = pathFormat.Replace("{hh}", DateTime.Now.Hour.ToString("D2"));
            pathFormat = pathFormat.Replace("{ii}", DateTime.Now.Minute.ToString("D2"));
            pathFormat = pathFormat.Replace("{ss}", DateTime.Now.Second.ToString("D2"));
            return pathFormat + extension;
        }
    }

    public class UploadConfig
    {
        public string PathFormat { get; set; }
        public string UploadFieldName { get; set; }
        public int SizeLimit { get; set; }
        public List<string> AllowExtensions { get; set; }
        public bool Base64 { get; set; }
        public string Base64Filename { get; set; }

    }


    public static class Config
    {
        public static string ConfigFile { get; set; } = "Configs/ueditor.json";

        public static bool noCache { get; set; } = true;

        private static JObject BuildItems()
        {
            string json = File.ReadAllText(Config.ConfigFile);
            return JObject.Parse(json);
        }


        public static JObject Items
        {
            get
            {
                bool flag = Config.noCache || Config._Items == null;
                if (flag)
                {
                    Config._Items = Config.BuildItems();
                }
                return Config._Items;
            }
        }


        public static T GetValue<T>(string key)
        {
            return Config.Items[key].Value<T>();
        }

        public static string[] GetStringList(string key)
        {
            return (from x in Config.Items[key]
                    select x.Value<string>()).ToArray<string>();
        }

        public static string GetString(string key)
        {
            return Config.GetValue<string>(key);
        }

        public static int GetInt(string key)
        {
            return Config.GetValue<int>(key);
        }


        private static JObject _Items;
    }
}